﻿Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Printing
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Windows.Forms
Imports System.Workflow.Interop

Namespace System.Workflow.ComponentModel.Design
    <ToolboxItem(False)> _
    Friend NotInheritable Class WorkflowPrintDocument
        Inherits PrintDocument
        ' Methods
        Public Sub New(ByVal workflowView As WorkflowView)
            Me.workflowView = workflowView
            Me.previewLayout = New PrintPreviewLayout(Me.workflowView, Me)
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try 
                If (disposing AndAlso (Not Me.previewLayout Is Nothing)) Then
                    Me.previewLayout.Dispose
                    Me.previewLayout = Nothing
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub

        Friend Function GetHardMargins(ByVal graphics As Graphics) As Margins
            Dim hdc As IntPtr = graphics.GetHdc
            Dim point As New Point(Math.Max(NativeMethods.GetDeviceCaps(hdc, &H58), 1), Math.Max(NativeMethods.GetDeviceCaps(hdc, 90), 1))
            Dim num As Integer = CInt(((NativeMethods.GetDeviceCaps(hdc, 8) * 100!) / CSng(point.X)))
            Dim num2 As Integer = CInt(((NativeMethods.GetDeviceCaps(hdc, 10) * 100!) / CSng(point.Y)))
            Dim num3 As Integer = CInt(((NativeMethods.GetDeviceCaps(hdc, 110) * 100!) / CSng(point.X)))
            Dim num4 As Integer = CInt(((NativeMethods.GetDeviceCaps(hdc, &H6F) * 100!) / CSng(point.Y)))
            Dim left As Integer = CInt(((NativeMethods.GetDeviceCaps(hdc, &H70) * 100!) / CSng(point.X)))
            Dim top As Integer = CInt(((NativeMethods.GetDeviceCaps(hdc, &H71) * 100!) / CSng(point.Y)))
            Dim right As Integer = ((num3 - num) - left)
            Dim bottom As Integer = ((num4 - num2) - top)
            graphics.ReleaseHdc(hdc)
            Return New Margins(left, right, top, bottom)
        End Function

        Private Function MoveNextPage() As Boolean
            Me.currentPrintablePage.X += 1
            If (Me.currentPrintablePage.X < Me.totalPrintablePages.X) Then
                Return True
            End If
            Me.currentPrintablePage.X = 0
            Me.currentPrintablePage.Y += 1
            Return (Me.currentPrintablePage.Y < Me.totalPrintablePages.Y)
        End Function

        Protected Overrides Sub OnBeginPrint(ByVal printArgs As PrintEventArgs)
            MyBase.OnBeginPrint(printArgs)
            Me.currentPrintablePage = Point.Empty
            Dim flag As Boolean = ((MyBase.PrinterSettings.IsValid AndAlso (PrinterSettings.InstalledPrinters.Count > 0)) AndAlso New ArrayList(PrinterSettings.InstalledPrinters).Contains(MyBase.PrinterSettings.PrinterName))
            If Not flag Then
                DesignerHelpers.ShowError(Me.workflowView, DR.GetString("SelectedPrinterIsInvalidErrorMessage", New Object(0  - 1) {}))
            End If
            printArgs.Cancel = (Not flag OrElse (Me.workflowView.RootDesigner Is Nothing))
        End Sub

        Protected Overrides Sub OnPrintPage(ByVal printPageArg As PrintPageEventArgs)
            MyBase.OnPrintPage(printPageArg)
            Dim ambientTheme As AmbientTheme = WorkflowTheme.CurrentTheme.AmbientTheme
            Dim graphics As Graphics = printPageArg.Graphics
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
            graphics.SmoothingMode = SmoothingMode.HighQuality
            If Me.currentPrintablePage.IsEmpty Then
                Me.PrepareToPrint(printPageArg)
            End If
            Dim hardMargins As Margins = Me.GetHardMargins(graphics)
            Dim margins2 As New Margins(Math.Max(printPageArg.PageSettings.Margins.Left, hardMargins.Left), Math.Max(printPageArg.PageSettings.Margins.Right, hardMargins.Right), Math.Max(printPageArg.PageSettings.Margins.Top, hardMargins.Top), Math.Max(printPageArg.PageSettings.Margins.Bottom, hardMargins.Bottom))
            Dim size As New Size((printPageArg.PageBounds.Size.Width - (margins2.Left + margins2.Right)), (printPageArg.PageBounds.Size.Height - (margins2.Top + margins2.Bottom)))
            Dim rect As New Rectangle(margins2.Left, margins2.Top, size.Width, size.Height)
            Dim region As New Region(rect)
            Try 
                graphics.TranslateTransform(CSng(-hardMargins.Left), CSng(-hardMargins.Top))
                graphics.FillRectangle(ambientTheme.BackgroundBrush, rect)
                graphics.DrawRectangle(ambientTheme.ForegroundPen, rect)
                If (Not ambientTheme.WorkflowWatermarkImage Is Nothing) Then
                    ActivityDesignerPaint.DrawImage(graphics, ambientTheme.WorkflowWatermarkImage, rect, New Rectangle(Point.Empty, ambientTheme.WorkflowWatermarkImage.Size), ambientTheme.WatermarkAlignment, 0.25!, False)
                End If
                Dim transform As Matrix = graphics.Transform
                Dim clip As Region = graphics.Clip
                graphics.Clip = [region]
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
                Dim point As New Point(((Me.currentPrintablePage.X * size.Width) - Me.workflowAlignment.X), ((Me.currentPrintablePage.Y * size.Height) - Me.workflowAlignment.Y))
                graphics.TranslateTransform(CSng((rect.Left - point.X)), CSng((rect.Top - point.Y)))
                graphics.ScaleTransform(Me.scaling, Me.scaling)
                Dim empty As Size = Size.Empty
                empty.Width = Convert.ToInt32(Math.Ceiling(CDbl((CSng(size.Width) / Me.scaling))))
                empty.Height = Convert.ToInt32(Math.Ceiling(CDbl((CSng(size.Height) / Me.scaling))))
                Dim point2 As Point = Point.Empty
                point2.X = Convert.ToInt32(Math.Ceiling(CDbl((CSng(Me.workflowAlignment.X) / Me.scaling))))
                point2.Y = Convert.ToInt32(Math.Ceiling(CDbl((CSng(Me.workflowAlignment.Y) / Me.scaling))))
                Dim viewPort As New Rectangle(((Me.currentPrintablePage.X * empty.Width) - point2.X), ((Me.currentPrintablePage.Y * empty.Height) - point2.Y), empty.Width, empty.Height)
                DirectCast(Me.workflowView.RootDesigner, IWorkflowDesignerMessageSink).OnPaint(New PaintEventArgs(graphics, Me.workflowView.RootDesigner.Bounds), viewPort)
                graphics.Clip = clip
                graphics.Transform = transform
                Dim headerFooterPrintData As New HeaderFooterData { _
                    .Font = ambientTheme.Font, _
                    .PageBounds = printPageArg.PageBounds, _
                    .PageBoundsWithoutMargin = rect, _
                    .HeaderFooterMargins = New Margins(0, 0, Me.pageSetupData.HeaderMargin, Me.pageSetupData.FooterMargin), _
                    .PrintTime = Me.printTime, _
                    .CurrentPage = ((Me.currentPrintablePage.X + (Me.currentPrintablePage.Y * Me.totalPrintablePages.X)) + 1), _
                    .TotalPages = (Me.totalPrintablePages.X * Me.totalPrintablePages.Y), _
                    .Scaling = Me.scaling _
                }
                Dim service As WorkflowDesignerLoader = [TryCast](DirectCast(Me.workflowView, IServiceProvider).GetService(GetType(WorkflowDesignerLoader)),WorkflowDesignerLoader)
                headerFooterPrintData.FileName = If((Not service Is Nothing), service.FileName, String.Empty)
                If (Me.pageSetupData.HeaderTemplate.Length > 0) Then
                    Me.PrintHeaderFooter(graphics, True, headerFooterPrintData)
                End If
                If (Me.pageSetupData.FooterTemplate.Length > 0) Then
                    Me.PrintHeaderFooter(graphics, False, headerFooterPrintData)
                End If
                printPageArg.HasMorePages = Me.MoveNextPage
            Catch exception As Exception
                DesignerHelpers.ShowError(Me.workflowView, (DR.GetString("SelectedPrinterIsInvalidErrorMessage", New Object(0  - 1) {}) & ChrW(10) & exception.Message))
                printPageArg.Cancel = True
                printPageArg.HasMorePages = False
            Finally
                [region].Dispose
            End Try
            If Not printPageArg.HasMorePages Then
                Me.workflowView.PerformLayout
            End If
        End Sub

        Private Sub PrepareToPrint(ByVal printPageArg As PrintPageEventArgs)
            Dim size4 As Size
            Dim graphics As Graphics = printPageArg.Graphics
            Dim selectionSize As Size = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize
            DirectCast(Me.workflowView.RootDesigner, IWorkflowDesignerMessageSink).OnLayoutSize(graphics)
            DirectCast(Me.workflowView.RootDesigner, IWorkflowDesignerMessageSink).OnLayoutPosition(graphics)
            Me.workflowView.RootDesigner.Location = Point.Empty
            Dim size As Size = Me.workflowView.RootDesigner.Size
            size.Width = (size.Width + (3 * selectionSize.Width))
            size.Height = (size.Height + (3 * selectionSize.Height))
            Dim size3 As Size = printPageArg.PageBounds.Size
            Dim hardMargins As Margins = Me.GetHardMargins(graphics)
            Dim margins2 As New Margins(Math.Max(printPageArg.PageSettings.Margins.Left, hardMargins.Left), Math.Max(printPageArg.PageSettings.Margins.Right, hardMargins.Right), Math.Max(printPageArg.PageSettings.Margins.Top, hardMargins.Top), Math.Max(printPageArg.PageSettings.Margins.Bottom, hardMargins.Bottom))
            size4 = New Size((size3.Width - (margins2.Left + margins2.Right)), (size3.Height - (margins2.Top + margins2.Bottom))) { _
                .Width = Math.Max(size4.Width, 1), _
                .Height = Math.Max(size4.Height, 1) _
            }
            If Me.pageSetupData.AdjustToScaleFactor Then
                Me.scaling = (CSng(Me.pageSetupData.ScaleFactor) / 100!)
            Else
                Dim num As Single = ((Me.pageSetupData.PagesWide * size4.Width) / CSng(size.Width))
                Dim num2 As Single = ((Me.pageSetupData.PagesTall * size4.Height) / CSng(size.Height))
                Me.scaling = Math.Min(num, num2)
                Me.scaling = CSng((Math.Floor(CDbl((Me.scaling * 1000))) / 1000))
            End If
            Me.totalPrintablePages.X = Convert.ToInt32(Math.Ceiling(CDbl(((Me.scaling * size.Width) / CSng(size4.Width)))))
            Me.totalPrintablePages.X = Math.Max(Me.totalPrintablePages.X, 1)
            Me.totalPrintablePages.Y = Convert.ToInt32(Math.Ceiling(CDbl(((Me.scaling * size.Height) / CSng(size4.Height)))))
            Me.totalPrintablePages.Y = Math.Max(Me.totalPrintablePages.Y, 1)
            Me.workflowAlignment = Point.Empty
            If Me.pageSetupData.CenterHorizontally Then
                Me.workflowAlignment.X = CInt((((((Me.totalPrintablePages.X * size4.Width) / Me.scaling) - size.Width) / 2!) * Me.scaling))
            End If
            If Me.pageSetupData.CenterVertically Then
                Me.workflowAlignment.Y = CInt((((((Me.totalPrintablePages.Y * size4.Height) / Me.scaling) - size.Height) / 2!) * Me.scaling))
            End If
            Me.workflowAlignment.X = Math.Max(Me.workflowAlignment.X, (selectionSize.Width + (selectionSize.Width / 2)))
            Me.workflowAlignment.Y = Math.Max(Me.workflowAlignment.Y, (selectionSize.Height + (selectionSize.Height / 2)))
            Me.printTime = DateTime.Now
        End Sub

        Friend Sub PrintHeaderFooter(ByVal graphics As Graphics, ByVal drawHeader As Boolean, ByVal headerFooterPrintData As HeaderFooterData)
            Dim text As String = If(drawHeader, Me.pageSetupData.HeaderTemplate, Me.pageSetupData.FooterTemplate)
            Dim strArray As String() = [text].Replace("{#}", headerFooterPrintData.CurrentPage.ToString(CultureInfo.CurrentCulture)).Replace("{##}", headerFooterPrintData.TotalPages.ToString(CultureInfo.CurrentCulture)).Replace("{Date}", headerFooterPrintData.PrintTime.ToShortDateString).Replace("{Time}", headerFooterPrintData.PrintTime.ToShortTimeString).Replace("{FullFileName}", headerFooterPrintData.FileName).Replace("{FileName}", Path.GetFileName(headerFooterPrintData.FileName)).Replace("{User}", SystemInformation.UserName).Split(New Char() { ChrW(10), ChrW(13) }, 6, StringSplitOptions.RemoveEmptyEntries)
            Dim builder As New StringBuilder
            Dim i As Integer
            For i = 0 To Math.Min(strArray.Length, 5) - 1
                builder.Append(strArray(i))
                builder.Append(ChrW(13) & ChrW(10))
            Next i
            [text] = builder.ToString
            Dim empty As Rectangle = Rectangle.Empty
            Dim ef As SizeF = graphics.MeasureString([text], headerFooterPrintData.Font)
            empty.Size = New Size(Convert.ToInt32(Math.Ceiling(CDbl(ef.Width))), Convert.ToInt32(Math.Ceiling(CDbl(ef.Height))))
            empty.Width = Math.Min(headerFooterPrintData.PageBoundsWithoutMargin.Width, empty.Width)
            Dim alignment As HorizontalAlignment = If(drawHeader, Me.pageSetupData.HeaderAlignment, Me.pageSetupData.FooterAlignment)
            Dim format As New StringFormat { _
                .Trimming = StringTrimming.EllipsisCharacter _
            }
            Select Case alignment
                Case HorizontalAlignment.Left
                    empty.X = headerFooterPrintData.PageBoundsWithoutMargin.Left
                    format.Alignment = StringAlignment.Near
                    Exit Select
                Case HorizontalAlignment.Right
                    empty.X = (headerFooterPrintData.PageBoundsWithoutMargin.Left + (headerFooterPrintData.PageBoundsWithoutMargin.Width - empty.Width))
                    format.Alignment = StringAlignment.Far
                    Exit Select
                Case HorizontalAlignment.Center
                    empty.X = (headerFooterPrintData.PageBoundsWithoutMargin.Left + ((headerFooterPrintData.PageBoundsWithoutMargin.Width - empty.Width) / 2))
                    format.Alignment = StringAlignment.Center
                    Exit Select
            End Select
            If drawHeader Then
                empty.Y = (headerFooterPrintData.PageBounds.Top + headerFooterPrintData.HeaderFooterMargins.Top)
                format.LineAlignment = StringAlignment.Near
            Else
                empty.Y = ((headerFooterPrintData.PageBounds.Bottom - headerFooterPrintData.HeaderFooterMargins.Bottom) - empty.Size.Height)
                format.LineAlignment = StringAlignment.Far
            End If
            graphics.DrawString([text], headerFooterPrintData.Font, WorkflowTheme.CurrentTheme.AmbientTheme.ForegroundBrush, empty, format)
        End Sub


        ' Properties
        Friend ReadOnly Property PageSetupData As PageSetupData
            Get
                Return Me.pageSetupData
            End Get
        End Property

        Friend ReadOnly Property PrintPreviewLayout As PrintPreviewLayout
            Get
                Return Me.previewLayout
            End Get
        End Property


        ' Fields
        Private currentPrintablePage As Point = Point.Empty
        Private Const MaxHeaderFooterLines As Integer = 5
        Private pageSetupData As PageSetupData = New PageSetupData
        Private previewLayout As PrintPreviewLayout
        Private printTime As DateTime
        Private scaling As Single
        Private totalPrintablePages As Point = Point.Empty
        Private workflowAlignment As Point = Point.Empty
        Private workflowView As WorkflowView

        ' Nested Types
        Friend NotInheritable Class HeaderFooterData
            ' Fields
            Friend CurrentPage As Integer
            Friend FileName As String
            Friend Font As Font
            Friend HeaderFooterMargins As Margins
            Friend PageBounds As Rectangle
            Friend PageBoundsWithoutMargin As Rectangle
            Friend PrintTime As DateTime
            Friend Scaling As Single
            Friend TotalPages As Integer
        End Class
    End Class
End Namespace

